package cn.nr19.jian.`object`

import cn.nr19.jian.J2Utils
import cn.nr19.jian.Jian
import cn.nr19.jian.exception.ParserException
import cn.nr19.jian.`object`.annotation.JianFun
import cn.nr19.jian.token.ARRNode
import cn.nr19.jian.token.BooleanNode
import cn.nr19.jian.token.ENode
import cn.nr19.jian.token.EONNode
import cn.nr19.jian.token.NULL
import cn.nr19.jian.token.NumNode
import cn.nr19.jian.token.StrNode

open class EON : HashMap<String,Any>, JianObject {

    constructor()

    // 存入
    constructor(vs : Map<String,Any>){
        putAll(vs)
    }

    // 节点解析成基本信息、str/num 存放实际值
    constructor(v : EONNode){
        v.datas.forEach {
            when(it.value.nodeType()){
                ENode.str -> put(it.key,(it.value as StrNode).value)
                ENode.num-> put(it.key,(it.value as NumNode).value)
                ENode.boolean -> put(it.key,(it.value as BooleanNode).value)
                ENode.arr -> put(it.key,ARR(it.value as ARRNode))
                ENode.eon -> put(it.key,EON(it.value as EONNode))
                else -> put(it.key,it.value)
            }
        }
    }

    // eon文本到对象
    constructor(v : String) : this(EONNode(v))
    override fun pFun(data: JianLeiApi,name: String, pars: List<Any>): Any? {
        return when(name){
            "设","设置" -> {
                if (pars.size == 2){
                    put(pars[0].toString(),pars[1])
                    return true
                }else{
                    return super.pFun(data,name, pars)
                }
            }
            else -> super.pFun(data,name, pars)
        }
    }
    override fun getPar(name: String, data: JianLeiApi?): Any {
        return super.getPar(name, data)?:get(name)?:NULL() // 允许
    }
    override fun toString(): String {
        return toString(true)
    }

    /**
     * @param isN 间隔换行(true)或逗号(false)
     * @param jumpNull 跳过空
     */
    fun toString(dakuohao : Boolean,isN : Boolean = false,jumpNull: Boolean = false) : String{
        val ks = StringBuilder()
        forEach {
            if (it.value == this){
                throw ParserException("什么神仙操作  自己赋值给自己？？？",0)
            }
            if (!jumpNull || !Jian.isEmpty(it.value)){
                val v : String = when(it.value){
                    is Number -> it.value.toString()
                    is cn.nr19.jian.token.Node -> it.value.toString()
                    is EON -> it.value.toString()
                    is ARR -> it.value.toString()
                    is Boolean -> it.value.toString()
                    else -> J2Utils.toString(it.value.toString())
                }

                if (!J2Utils.isKEYorNumber(it.key)){
                    ks.append("\"").append(it.key).append("\"")
                }else{
                    ks.append(it.key)
                }

                ks.append(":")
                    .append(v)

                if (isN) ks.append("\n")
                else ks.append(",")
            }
        }

        if (ks.length > 1) ks.delete(ks.length - 1,ks.length)
        if (dakuohao) return "{$ks}"
        else return ks.toString()
    }





    @JianFun("参数1=成员名称:文本类型：；返回=逻辑：成员存在返回真，否则返回假")
    open fun 成员是否存在(k : String) : Boolean{
        return containsKey(k)
    }

    @JianFun("取所有成员名称，返回=数组<字符串>：成员名称数组")
    open fun 取所有键() : ARR{
        val ls = ARR()
        forEach {
            ls.add(it.key)
        }
        return ls
    }

    @JianFun("参数1=键名:文本类型：；返回=键对应的数据")
    open fun 取(键名 : String) : Any{
        return get(键名) ?: NULL()
    }

    @JianFun("参数1=键名:文本类型：；返回=键对应的数据")
    open fun 读(k : String) : Any{
        return 取(k)
    }

    @JianFun("返回=项目数()和成员数() 返回的结果一致，均为成员数量。")
    open fun 项目数() : Int {
        return size
    }

    @JianFun("返回=项目数()和成员数() 返回的结果一致，均为成员数量。")
    open fun 成员数() : Int {
        return size
    }

    @JianFun("返回=输出文本。")
    open fun 到文本() : String = toString()

    @JianFun("删除指定成员； 参数1：成员名称")
    open fun 删除(k : String) : Boolean{
        if (containsKey(k)) remove(k)
        return true
    }

    @JianFun("删除所有成员")
    open fun 清空() : Boolean{
        clear()
        return true
    }

    @JianFun("合并为字符串;参数1:字符串=成员之间的分界符号")
    open fun 合并(k : String) : String{
        if (size == 0) return ""
        StringBuilder().let {str->

            forEach {
                str.append(it.toString()).append(k)
            }

            // 去尾符k
            if (size > 1 && k.isNotEmpty()){
                str.delete(str.length - k.length,k.length)
            }

            return toString()
        }
    }

    // ********************************************************
    //*********** 便利接口 **************************
    /**
     * @param qiangzhi 强制转换为str
     */
    fun getStr(key : String,qiangzhi : Boolean = false) : String?{
        val v = get(key) ?: return null
        if (v is String) return v
        else if (v is StrNode) return v.value
        else if (qiangzhi) return v.toString()
        else return null
    }
    fun getInt(key : String,qiangzhi : Boolean = false) : Int?{
        val v = get(key) ?: return null
        if (v is Int) return v
        else if (v is Float) return v.toInt()
        else if (v is Double) return v.toInt()
        else if (qiangzhi) return Jian.toInt(v)
        else return null
    }
    fun getFloat(key : String,qiangzhi: Boolean = false) : Float?{
        val v = get(key) ?: return null
        if (v is Float) return v
        else if (v is Int) return v.toFloat()
        else if (qiangzhi) return qiangzhi.toString().toFloat()
        else return null
    }
    fun getBoolean(key : String, qiangzhi: Boolean = false) : Boolean?{
        val v = get(key) ?: return null
        if (v is Boolean) return v
        else if (v is Int) return v == 1
        else if (qiangzhi) return v.toString() == "true"
        else return null
    }
    fun getArr(key :String) : ARR?{
        get(key).let {
            if (it is ARR) return it
            else return null
        }
    }
    fun getEON(key :String) : EON?{
        get(key).let {
            if (it is EON) return it
            else return null
        }
    }
    fun int(key: String,def : Int) : Int{
        return getInt(key)?:def
    }
    fun str(key: String,def : String) : String{
        return getStr(key) ?: def
    }
    fun boolean(key: String, def : Boolean) : Boolean{
        return getBoolean(key) ?: def
    }
    fun put(key : String,v : Any?) : EON {
        if (v == null) remove(key)
        else set(key,v)
        return this
    }
}